<?php

declare(strict_types=1);

namespace App\Traits;

use flight\Engine;
use JustSteveKing\StatusCode\Http;

/**
 * Extensión para realizar respuestas HTTP simples.
 */
trait ResponseTrait
{
    /**
     * Método abstracto dependiente que obtiene una instancia de la aplicación.
     */
    abstract protected function app(): Engine;

    private array $body = [];

    /**
     * Genera una respuesta genérica.
     */
    protected function respond(mixed $data, string $description, ?int $status = null): void
    {
        $status ??= Http::OK();

        $response = array_merge($this->body, [
            'data' => $data,
            'status' => $status,
            'description' => $description,
        ]);

        $this->body = [];

        $this->app()->jsonHalt($response, $status);
    }

    /**
     * Genera una respuesta genérica de errores o fallos.
     */
    protected function respondFail(string $description, ?int $status = null, string $error = 'Bad Request'): void
    {
        $status ??= Http::BAD_REQUEST();

        $this->body['error'] = $error;

        $this->respond(null, $description, $status);
    }

    /**
     * Genera una respuesta de errores de servidor.
     */
    protected function respondServerError(array $trace, string $description, string $error = 'Internal Server Error'): void
    {
        $this->body['stack_traces'] = $trace;

        $this->respondFail($description, Http::INTERNAL_SERVER_ERROR(), $error);
    }

    /**
     * Genera una respuesta al no encontrar un recurso.
     */
    protected function respondNotFound(string $description, string $error = 'Not Found'): void
    {
        $this->respondFail($description, Http::NOT_FOUND(), $error);
    }

    /**
     * Genera una respuesta de errores de validación.
     */
    protected function respondValidationError(array $validations, string $description, string $error = 'Validation error'): void
    {
        $this->body['validations'] = $validations;

        $this->respondFail($description, Http::BAD_REQUEST(), $error);
    }

    /**
     * Genera una respuesta al crear un nuevo recurso.
     */
    protected function respondCreate(mixed $data, string $description): void
    {
        $this->respond($data, $description, Http::CREATED());
    }

    /**
     * Genera una respuesta cuando se intenta crear un recurso que ya existe.
     */
    protected function respondResourceExists(string $description, string $error = 'Conflict'): void
    {
        $this->respondFail($description, Http::CONFLICT(), $error);
    }
}
